package server

import (
	"context"
	"database/sql"
	"fmt"
	"sync"
	"time"

	"hawkeye/common/logger"
	"hawkeye/common/storage"
	"hawkeye/config"
	"hawkeye/event"
	"hawkeye/monitor"
	"hawkeye/protocol"
	"hawkeye/server/handles"
	"hawkeye/server/model"

	"github.com/gookit/slog"
	"github.com/gookit/slog/handler"
	"github.com/panjf2000/gnet/v2"
	"gorm.io/gorm"
)

// Server TCP服务器简化实现
type Server struct {
	config      *config.Config
	eventMgr    *event.Manager
	dbManager   *gorm.DB
	eng         gnet.Engine
	connMutex   sync.RWMutex
	connections map[gnet.Conn]string // 连接 -> 客户端ID映射
	stopChan    chan struct{}
}

// NewServer 创建新的TCP服务器
func NewServer(cfg *config.Config) *Server {
	return &Server{
		config:      cfg,
		eventMgr:    event.NewManager(),
		dbManager:   storage.GDB,
		connections: make(map[gnet.Conn]string),
		stopChan:    make(chan struct{}),
	}
}

// OnBoot 服务器启动时调用
func (s *Server) OnBoot(eng gnet.Engine) (action gnet.Action) {
	s.eng = eng
	logger.Info(fmt.Sprintf("Starting server, listening at: %s:%d", s.config.Server.Host, s.config.Server.Port))

	// 初始化数据库连接
	if err := s.initDatabase(); err != nil {
		logger.Error(fmt.Sprintf("初始化数据库连接失败: %v", err))
		return gnet.Shutdown
	}

	// 注册默认事件处理器
	s.registerDefaultHandlers()

	// 启动心跳检测
	go s.startHeartbeatCheck()

	// 启动代理心跳检测
	go s.CheckAgentStatus()

	// 启动资源占用检测
	resourceMonitor := &monitor.Resource{}
	go resourceMonitor.ResourceMonitor()

	return gnet.None
}

// OnShutdown 服务器关闭时调用
func (s *Server) OnShutdown(eng gnet.Engine) {
	logger.Info("Server shutting down")

	// 关闭数据库连接
	if s.dbManager != nil {
		if err := storage.Close(s.dbManager); err != nil {
			logger.Error(fmt.Sprintf("关闭数据库连接失败: %v", err))
		} else {
			logger.Info("数据库连接已关闭")
		}
	}

	close(s.stopChan)
}

// OnOpen 新连接建立时调用
func (s *Server) OnOpen(c gnet.Conn) (out []byte, action gnet.Action) {
	s.connMutex.Lock()
	s.connections[c] = "" // 初始客户端ID为空
	s.connMutex.Unlock()

	logger.Info(fmt.Sprintf("New connection: %s", c.RemoteAddr().String()))
	return nil, gnet.None
}

// OnClose 连接关闭时调用
func (s *Server) OnClose(c gnet.Conn, err error) (action gnet.Action) {
	s.connMutex.Lock()
	delete(s.connections, c)
	s.connMutex.Unlock()

	logger.Info(fmt.Sprintf("Connection closed: %s", c.RemoteAddr().String()))
	return gnet.None
}

// OnTraffic 数据到达时调用
func (s *Server) OnTraffic(c gnet.Conn) (action gnet.Action) {
	// 读取所有可用数据
	data, err := c.Next(-1)
	if err != nil {
		logger.Error(fmt.Sprintf("读取数据失败: %v", err))
		return gnet.Close
	}

	if len(data) == 0 {
		return gnet.None
	}

	// 处理粘包问题：解析多个消息
	offset := 0
	for offset < len(data) {
		// 检查是否有足够的数据读取消息头（4字节）
		if len(data)-offset < 4 {
			break
		}

		// 解析消息长度
		length := uint32(data[offset])<<24 | uint32(data[offset+1])<<16 |
			uint32(data[offset+2])<<8 | uint32(data[offset+3])

		// 检查长度是否合理
		if length == 0 || length > 10*1024*1024 {
			logger.Error(fmt.Sprintf("无效的消息长度: %d", length))
			return gnet.Close
		}

		// 检查是否收到完整的消息
		if len(data)-offset < 4+int(length) {
			break // 等待更多数据
		}

		// 提取单个消息
		messageData := data[offset : offset+4+int(length)]
		offset += 4 + int(length)

		// 处理单个消息
		go s.handleMessage(c, messageData)
	}

	// 如果还有未处理的数据，保留在缓冲区中
	if offset < len(data) {
		// 在gnet v2中，Next(-1)已经消耗了所有数据
		// 我们需要手动管理缓冲区，将未处理的数据放回
		remaining := data[offset:]
		if len(remaining) > 0 {
			// 将剩余数据写回连接，供下次处理
			_, err = c.Write(remaining)
			if err != nil {
				logger.Error(fmt.Sprintf("写回剩余数据失败: %v", err))
				return gnet.Close
			}
		}
	}

	return gnet.None
}

// OnTick 定时器触发时调用
func (s *Server) OnTick() (delay time.Duration, action gnet.Action) {
	return time.Second, gnet.None
}

// handleMessage 处理接收到的消息
func (s *Server) handleMessage(c gnet.Conn, data []byte) {
	// 解码消息
	msg, err := protocol.DecodeMessage(data)
	if err != nil {
		logger.Error(fmt.Sprintf("消息解码失败: %v", err))
		return
	}

	// 设置时间戳
	msg.Timestamp = time.Now().UnixNano()

	// 创建事件上下文
	ctx := event.NewContext(c.RemoteAddr().String(), c.RemoteAddr().String(), msg)

	// 分发事件处理
	err = s.eventMgr.HandleEvent(ctx, msg.Event, msg.Data)
	if err != nil {
		logger.Error(fmt.Sprintf("事件处理失败: %v", err))
	}
}

// SendMessageToConnection 向指定连接发送消息
func (s *Server) SendMessageToConnection(c gnet.Conn, msg *protocol.Message) error {
	// 设置消息序列号和时间戳
	msg.Sequence = uint64(time.Now().UnixNano())
	msg.Timestamp = time.Now().UnixNano()

	// 编码消息
	data, err := protocol.EncodeMessage(msg)
	if err != nil {
		return err
	}

	// 发送消息
	_, err = c.Write(data)
	return err
}

// BroadcastMessage 广播消息给所有连接
func (s *Server) BroadcastMessage(msg *protocol.Message) error {
	s.connMutex.RLock()
	defer s.connMutex.RUnlock()

	var lastErr error
	for conn := range s.connections {
		if err := s.SendMessageToConnection(conn, msg); err != nil {
			lastErr = err
		}
	}

	return lastErr
}

// GetConnectionCount 获取当前连接数
func (s *Server) GetConnectionCount() int {
	s.connMutex.RLock()
	defer s.connMutex.RUnlock()
	return len(s.connections)
}

// Start 启动服务器
func (s *Server) Start() error {
	addr := fmt.Sprintf("%s:%d", s.config.Server.Host, s.config.Server.Port)
	return gnet.Run(s, addr,
		gnet.WithMulticore(true),
		gnet.WithTCPKeepAlive(time.Minute),
		gnet.WithSocketRecvBuffer(s.config.Server.ReadBufferSize),
		gnet.WithSocketSendBuffer(s.config.Server.WriteBufferSize),
		gnet.WithTicker(true),
	)
}

// Stop 停止服务器
func (s *Server) Stop() {
	s.eng.Stop(context.Background())
}

// registerDefaultHandlers 注册默认事件处理器
func (s *Server) registerDefaultHandlers() {
	// 创建处理器实例
	heartbeatHandler := handles.NewHeartbeatHandler(&s.connMutex, s.connections)
	authHandler := handles.NewAuthHandler(&s.connMutex, s.connections)
	registerHandler := handles.NewRegisterHandler(&s.connMutex, s.connections)

	// 注册处理器
	s.eventMgr.RegisterHandler(protocol.EventHeartbeat, heartbeatHandler.Handle)
	s.eventMgr.RegisterHandler(protocol.EventAuth, authHandler.Handle)
	s.eventMgr.RegisterHandler(protocol.EvenRegister, registerHandler.Handle)
}

// initDatabase 初始化数据库连接
func (s *Server) initDatabase() error {

	// 连接数据库
	storage.InitGDb(s.config.Database)
	s.dbManager = storage.GDB

	// 测试连接
	if err := storage.TestConnection(s.dbManager); err != nil {
		return fmt.Errorf("数据库连接测试失败: %v", err)
	}

	logger.Info("MySQL数据库连接成功")

	// 输出连接统计信息
	stats := storage.GetConnectionStats(s.dbManager)
	if dbStats, ok := stats.(sql.DBStats); ok {
		logger.Info(fmt.Sprintf("数据库连接池统计: 最大连接数=%d, 当前连接数=%d",
			dbStats.MaxOpenConnections, dbStats.OpenConnections))
	}

	return nil
}

// GetDatabaseManager 获取数据库管理器
func (s *Server) GetDatabaseManager() *gorm.DB {
	return s.dbManager
}

// IsDatabaseConnected 检查数据库是否连接
func (s *Server) IsDatabaseConnected() bool {
	if s.dbManager == nil {
		return false
	}
	return storage.IsConnected(s.dbManager)
}

// startHeartbeatCheck 启动心跳检测
func (s *Server) startHeartbeatCheck() {
	perfLogger := slog.NewWithHandlers(handler.MustFileHandler("logs/perf_active_conn.log", handler.WithLogLevels(slog.AllLevels)))
	ticker := time.NewTicker(s.config.Server.HeartbeatInterval)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			// 简单的心跳检测逻辑
			perfLogger.Info(fmt.Sprintf("当前活跃连接数: %d", s.GetConnectionCount()))

			// 检查数据库连接状态
			if !s.IsDatabaseConnected() {
				perfLogger.Info("数据库连接断开，尝试重连...")
				if err := s.initDatabase(); err != nil {
					perfLogger.Error(fmt.Sprintf("数据库重连失败: %v", err))
				} else {
					perfLogger.Info("数据库重连成功")
				}
			}
		case <-s.stopChan:
			return
		}
	}
}

// 每分钟检测一下agent的状态，如果超过10分钟没有心跳，则认为agent离线
func (s *Server) CheckAgentStatus() {
	ticker := time.NewTicker(s.config.Server.HeartbeatInterval)

	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			var agent []model.Agent
			storage.GDB.Select("*").Find(&agent, "agent_status = ?", 1)
			// storage.GDB.Model(&model.Agent{}).Where("last_heartbeat_dt < ?", time.Now().Add(-10*time.Minute)).Updates(map[string]any{"agent_status": 0})
			for _, a := range agent {
				if a.LastHeartbeatDt.Before(time.Now().Add(-10 * time.Minute)) {
					logger.Warn(fmt.Sprintf("agent_id: %d, last_heartbeat_dt: %v", a.ID, a.LastHeartbeatDt))
					storage.GDB.Model(&model.Agent{}).Where("id = ?", a.ID).Updates(map[string]any{"agent_status": 0})
				}
			}
		case <-s.stopChan:
			return
		}
	}
}
